{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Transfer learning with VGG-16\n",
    "\n",
    "VGG-16[2] as a feature extractor.\n",
    "\n",
    "<img src=\"vgg16.png\">\n",
    "\n",
    "## References\n",
    "\n",
    "- [1] \"Hands-On Transfer Learning with Python - Implement Advanced Deep Learning and Neural Network Models Using Tensorflow and Keras\" \n",
    "- [2] \"Very Deep Convolutional Networks for Large-Scale Image Recognition\", Karen Simonyan and Andrew Zisserman (2014)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import glob\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "from tensorflow.keras.preprocessing.image import ImageDataGenerator, load_img, img_to_array, array_to_img\n",
    "%matplotlib inline"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Dataset preparation"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "def build_dataset(dataset_path,training_path_prefix,test_path_prefix,target_size,batch_size):   \n",
    "    train_datagen = ImageDataGenerator(\n",
    "        rescale=1./255, \n",
    "        zoom_range=0.3, \n",
    "        rotation_range=90,\n",
    "        width_shift_range=0.05, \n",
    "        height_shift_range=0.05, \n",
    "        shear_range=0.2, \n",
    "        horizontal_flip=True, \n",
    "        vertical_flip=True, \n",
    "        channel_shift_range=50.0,\n",
    "        fill_mode='nearest'\n",
    "    )\n",
    "    test_datagen = ImageDataGenerator(rescale=1./255)\n",
    "\n",
    "    training_set_generator = train_datagen.flow_from_directory(\n",
    "            dataset_path+training_path_prefix,\n",
    "            (INPUT_IMG_DIM,INPUT_IMG_DIM),\n",
    "            batch_size=BATCH_SIZE,\n",
    "            class_mode='categorical',\n",
    "            shuffle=True,\n",
    "            seed=42\n",
    "        )\n",
    "    test_set_generator = test_datagen.flow_from_directory(\n",
    "        dataset_path+test_path_prefix,\n",
    "        (INPUT_IMG_DIM,INPUT_IMG_DIM),\n",
    "        batch_size=BATCH_SIZE,\n",
    "        class_mode='categorical',\n",
    "        shuffle=True,\n",
    "        seed=42\n",
    "    )    \n",
    "    return training_set_generator, test_set_generator"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "INPUT_IMG_DIM = 120\n",
    "BATCH_SIZE = 32\n",
    "DATASET_PATH=\"../my_datasets/cracks_splitted8020/\"\n",
    "TRAINING_PATH_PREFIX=\"train_set\"\n",
    "TEST_PATH_PREFIX=\"test_set\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "training_set_generator, test_set_generator = build_dataset(\n",
    "    DATASET_PATH,\n",
    "    TRAINING_PATH_PREFIX,\n",
    "    TEST_PATH_PREFIX,\n",
    "    (INPUT_IMG_DIM,INPUT_IMG_DIM),\n",
    "    BATCH_SIZE\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## VGG-16"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from tensorflow.keras.applications import vgg16\n",
    "from tensorflow.keras.models import Model\n",
    "import tensorflow.keras\n",
    "\n",
    "\n",
    "# Base VGG\n",
    "vgg = vgg16.VGG16(\n",
    "    include_top=False, \n",
    "    weights='imagenet', \n",
    "    input_shape=(INPUT_IMG_DIM, INPUT_IMG_DIM, 3)\n",
    ")\n",
    "\n",
    "# Flatten output layer\n",
    "output = vgg.layers[-1].output\n",
    "output = tensorflow.keras.layers.Flatten()(output)\n",
    "\n",
    "vgg_model = Model(vgg.input, output)\n",
    "vgg_model.trainable = False"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Explore model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "_________________________________________________________________\n",
      "Layer (type)                 Output Shape              Param #   \n",
      "=================================================================\n",
      "input_1 (InputLayer)         (None, 120, 120, 3)       0         \n",
      "_________________________________________________________________\n",
      "block1_conv1 (Conv2D)        (None, 120, 120, 64)      1792      \n",
      "_________________________________________________________________\n",
      "block1_conv2 (Conv2D)        (None, 120, 120, 64)      36928     \n",
      "_________________________________________________________________\n",
      "block1_pool (MaxPooling2D)   (None, 60, 60, 64)        0         \n",
      "_________________________________________________________________\n",
      "block2_conv1 (Conv2D)        (None, 60, 60, 128)       73856     \n",
      "_________________________________________________________________\n",
      "block2_conv2 (Conv2D)        (None, 60, 60, 128)       147584    \n",
      "_________________________________________________________________\n",
      "block2_pool (MaxPooling2D)   (None, 30, 30, 128)       0         \n",
      "_________________________________________________________________\n",
      "block3_conv1 (Conv2D)        (None, 30, 30, 256)       295168    \n",
      "_________________________________________________________________\n",
      "block3_conv2 (Conv2D)        (None, 30, 30, 256)       590080    \n",
      "_________________________________________________________________\n",
      "block3_conv3 (Conv2D)        (None, 30, 30, 256)       590080    \n",
      "_________________________________________________________________\n",
      "block3_pool (MaxPooling2D)   (None, 15, 15, 256)       0         \n",
      "_________________________________________________________________\n",
      "block4_conv1 (Conv2D)        (None, 15, 15, 512)       1180160   \n",
      "_________________________________________________________________\n",
      "block4_conv2 (Conv2D)        (None, 15, 15, 512)       2359808   \n",
      "_________________________________________________________________\n",
      "block4_conv3 (Conv2D)        (None, 15, 15, 512)       2359808   \n",
      "_________________________________________________________________\n",
      "block4_pool (MaxPooling2D)   (None, 7, 7, 512)         0         \n",
      "_________________________________________________________________\n",
      "block5_conv1 (Conv2D)        (None, 7, 7, 512)         2359808   \n",
      "_________________________________________________________________\n",
      "block5_conv2 (Conv2D)        (None, 7, 7, 512)         2359808   \n",
      "_________________________________________________________________\n",
      "block5_conv3 (Conv2D)        (None, 7, 7, 512)         2359808   \n",
      "_________________________________________________________________\n",
      "block5_pool (MaxPooling2D)   (None, 3, 3, 512)         0         \n",
      "_________________________________________________________________\n",
      "flatten (Flatten)            (None, 4608)              0         \n",
      "=================================================================\n",
      "Total params: 14,714,688\n",
      "Trainable params: 0\n",
      "Non-trainable params: 14,714,688\n",
      "_________________________________________________________________\n"
     ]
    }
   ],
   "source": [
    "for layer in vgg_model.layers:\n",
    "    layer.trainable = False\n",
    "\n",
    "vgg_model.summary()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>Layer Type</th>\n",
       "      <th>Layer Name</th>\n",
       "      <th>Layer Trainable</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>&lt;tensorflow.python.keras.engine.input_layer.InputLayer object at 0x7f3f90e0f400&gt;</td>\n",
       "      <td>input_1</td>\n",
       "      <td>False</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>&lt;tensorflow.python.keras.layers.convolutional.Conv2D object at 0x7f3ee873e630&gt;</td>\n",
       "      <td>block1_conv1</td>\n",
       "      <td>False</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>&lt;tensorflow.python.keras.layers.convolutional.Conv2D object at 0x7f3f98f5f320&gt;</td>\n",
       "      <td>block1_conv2</td>\n",
       "      <td>False</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>&lt;tensorflow.python.keras.layers.pooling.MaxPooling2D object at 0x7f3ee873ef98&gt;</td>\n",
       "      <td>block1_pool</td>\n",
       "      <td>False</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>&lt;tensorflow.python.keras.layers.convolutional.Conv2D object at 0x7f3ee87470f0&gt;</td>\n",
       "      <td>block2_conv1</td>\n",
       "      <td>False</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>&lt;tensorflow.python.keras.layers.convolutional.Conv2D object at 0x7f3ee43c2cc0&gt;</td>\n",
       "      <td>block2_conv2</td>\n",
       "      <td>False</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>6</th>\n",
       "      <td>&lt;tensorflow.python.keras.layers.pooling.MaxPooling2D object at 0x7f3ee42a6400&gt;</td>\n",
       "      <td>block2_pool</td>\n",
       "      <td>False</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>7</th>\n",
       "      <td>&lt;tensorflow.python.keras.layers.convolutional.Conv2D object at 0x7f3ee42a6518&gt;</td>\n",
       "      <td>block3_conv1</td>\n",
       "      <td>False</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>8</th>\n",
       "      <td>&lt;tensorflow.python.keras.layers.convolutional.Conv2D object at 0x7f3ee44f97f0&gt;</td>\n",
       "      <td>block3_conv2</td>\n",
       "      <td>False</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>9</th>\n",
       "      <td>&lt;tensorflow.python.keras.layers.convolutional.Conv2D object at 0x7f3ee44706a0&gt;</td>\n",
       "      <td>block3_conv3</td>\n",
       "      <td>False</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>10</th>\n",
       "      <td>&lt;tensorflow.python.keras.layers.pooling.MaxPooling2D object at 0x7f3ee8789be0&gt;</td>\n",
       "      <td>block3_pool</td>\n",
       "      <td>False</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>11</th>\n",
       "      <td>&lt;tensorflow.python.keras.layers.convolutional.Conv2D object at 0x7f3ee8789438&gt;</td>\n",
       "      <td>block4_conv1</td>\n",
       "      <td>False</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>12</th>\n",
       "      <td>&lt;tensorflow.python.keras.layers.convolutional.Conv2D object at 0x7f3ee43ebf28&gt;</td>\n",
       "      <td>block4_conv2</td>\n",
       "      <td>False</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>13</th>\n",
       "      <td>&lt;tensorflow.python.keras.layers.convolutional.Conv2D object at 0x7f3ee4255ef0&gt;</td>\n",
       "      <td>block4_conv3</td>\n",
       "      <td>False</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>14</th>\n",
       "      <td>&lt;tensorflow.python.keras.layers.pooling.MaxPooling2D object at 0x7f3ee401d550&gt;</td>\n",
       "      <td>block4_pool</td>\n",
       "      <td>False</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>15</th>\n",
       "      <td>&lt;tensorflow.python.keras.layers.convolutional.Conv2D object at 0x7f3ee401d6a0&gt;</td>\n",
       "      <td>block5_conv1</td>\n",
       "      <td>False</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>16</th>\n",
       "      <td>&lt;tensorflow.python.keras.layers.convolutional.Conv2D object at 0x7f3ee6eda278&gt;</td>\n",
       "      <td>block5_conv2</td>\n",
       "      <td>False</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>17</th>\n",
       "      <td>&lt;tensorflow.python.keras.layers.convolutional.Conv2D object at 0x7f3ee6f0fba8&gt;</td>\n",
       "      <td>block5_conv3</td>\n",
       "      <td>False</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>18</th>\n",
       "      <td>&lt;tensorflow.python.keras.layers.pooling.MaxPooling2D object at 0x7f3ee6eb5240&gt;</td>\n",
       "      <td>block5_pool</td>\n",
       "      <td>False</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>19</th>\n",
       "      <td>&lt;tensorflow.python.keras.layers.core.Flatten object at 0x7f3ee5b4e208&gt;</td>\n",
       "      <td>flatten</td>\n",
       "      <td>False</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                                                                          Layer Type  \\\n",
       "0   <tensorflow.python.keras.engine.input_layer.InputLayer object at 0x7f3f90e0f400>   \n",
       "1   <tensorflow.python.keras.layers.convolutional.Conv2D object at 0x7f3ee873e630>     \n",
       "2   <tensorflow.python.keras.layers.convolutional.Conv2D object at 0x7f3f98f5f320>     \n",
       "3   <tensorflow.python.keras.layers.pooling.MaxPooling2D object at 0x7f3ee873ef98>     \n",
       "4   <tensorflow.python.keras.layers.convolutional.Conv2D object at 0x7f3ee87470f0>     \n",
       "5   <tensorflow.python.keras.layers.convolutional.Conv2D object at 0x7f3ee43c2cc0>     \n",
       "6   <tensorflow.python.keras.layers.pooling.MaxPooling2D object at 0x7f3ee42a6400>     \n",
       "7   <tensorflow.python.keras.layers.convolutional.Conv2D object at 0x7f3ee42a6518>     \n",
       "8   <tensorflow.python.keras.layers.convolutional.Conv2D object at 0x7f3ee44f97f0>     \n",
       "9   <tensorflow.python.keras.layers.convolutional.Conv2D object at 0x7f3ee44706a0>     \n",
       "10  <tensorflow.python.keras.layers.pooling.MaxPooling2D object at 0x7f3ee8789be0>     \n",
       "11  <tensorflow.python.keras.layers.convolutional.Conv2D object at 0x7f3ee8789438>     \n",
       "12  <tensorflow.python.keras.layers.convolutional.Conv2D object at 0x7f3ee43ebf28>     \n",
       "13  <tensorflow.python.keras.layers.convolutional.Conv2D object at 0x7f3ee4255ef0>     \n",
       "14  <tensorflow.python.keras.layers.pooling.MaxPooling2D object at 0x7f3ee401d550>     \n",
       "15  <tensorflow.python.keras.layers.convolutional.Conv2D object at 0x7f3ee401d6a0>     \n",
       "16  <tensorflow.python.keras.layers.convolutional.Conv2D object at 0x7f3ee6eda278>     \n",
       "17  <tensorflow.python.keras.layers.convolutional.Conv2D object at 0x7f3ee6f0fba8>     \n",
       "18  <tensorflow.python.keras.layers.pooling.MaxPooling2D object at 0x7f3ee6eb5240>     \n",
       "19  <tensorflow.python.keras.layers.core.Flatten object at 0x7f3ee5b4e208>             \n",
       "\n",
       "      Layer Name  Layer Trainable  \n",
       "0   input_1       False            \n",
       "1   block1_conv1  False            \n",
       "2   block1_conv2  False            \n",
       "3   block1_pool   False            \n",
       "4   block2_conv1  False            \n",
       "5   block2_conv2  False            \n",
       "6   block2_pool   False            \n",
       "7   block3_conv1  False            \n",
       "8   block3_conv2  False            \n",
       "9   block3_conv3  False            \n",
       "10  block3_pool   False            \n",
       "11  block4_conv1  False            \n",
       "12  block4_conv2  False            \n",
       "13  block4_conv3  False            \n",
       "14  block4_pool   False            \n",
       "15  block5_conv1  False            \n",
       "16  block5_conv2  False            \n",
       "17  block5_conv3  False            \n",
       "18  block5_pool   False            \n",
       "19  flatten       False            "
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import pandas as pd\n",
    "pd.set_option('max_colwidth', -1)\n",
    "\n",
    "layers = [(layer, layer.name, layer.trainable) for layer in vgg_model.layers]\n",
    "pd.DataFrame(layers, columns=['Layer Type', 'Layer Name', 'Layer Trainable'])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Trainable layers: []\n"
     ]
    }
   ],
   "source": [
    "print(\"Trainable layers:\", vgg_model.trainable_weights)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(1, 3, 3, 512)\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "<matplotlib.image.AxesImage at 0x7f3ee6d4b0b8>"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAQ8AAAD8CAYAAABpXiE9AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDMuMC4xLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvDW2N/gAADhRJREFUeJzt3X/MnWV9x/H3xxZoUFbQbtKUKpA1bgyXgB2iLqaZmmBH6BJZgn8oGMgzmWRqNA41wcRkmbrEZUYDaZAIiwEyNfC41BAcOFw2GJUUSmFAIZu0dqLFFeoPWN13fzw35vj4/Op17uec8+D7lZyc677v69zXl6vkw/2TpqqQpKP1knEXIGllMjwkNTE8JDUxPCQ1MTwkNTE8JDUZKjySvDzJ7Uke675Pmqffz5Ps6j7Tw4wpaTJkmOc8knwGeLqqPpXkSuCkqvrLOfodrqqXDVGnpAkzbHg8AmypqgNJ1gPfqqrXzNHP8JBeZIYNj/+pqhO7doAfvbA8q98RYBdwBPhUVd0yz/6mgCmAl6w+9nVr1v5Wc20vdqsO/njcJUy85151/LhLmHjPf3f/D6vqN1t+u3qxDkm+CZw8x6aPDy5UVSWZL4leXVX7k5wO3JFkd1U9PrtTVW0HtgO8dN3GOuP8Dy76D/Dr6sQb/m3cJUy8Rz96zrhLmHjfvfwj/9X620XDo6reOt+2JN9Psn7gtOWpefaxv/t+Ism3gLOAXwkPSSvHsLdqp4GLu/bFwK2zOyQ5KclxXXsd8CbgoSHHlTRmw4bHp4C3JXkMeGu3TJLNSa7t+vwusDPJ/cCdzFzzMDykFW7R05aFVNVB4C1zrN8JXNa1/xV47TDjSJo8PmEqqYnhIamJ4SGpieEhqYnhIamJ4SGpieEhqYnhIamJ4SGpieEhqYnhIamJ4SGpieEhqYnhIamJ4SGpieEhqYnhIamJ4SGpieEhqYnhIamJ4SGpieEhqYnhIamJ4SGpieEhqYnhIamJ4SGpSS/hkeS8JI8k2Zvkyjm2H5fk5m77PUlO7WNcSeMzdHgkWQV8AXg7cAbwziRnzOp2KfCjqvpt4G+BTw87rqTx6uPI4xxgb1U9UVXPAzcB22b12QZc37W/ArwlSXoYW9KY9BEeG4AnB5b3devm7FNVR4BDwCt6GFvSmEzUBdMkU0l2Jtl55Gc/Hnc5khbQR3jsBzYOLJ/SrZuzT5LVwFrg4OwdVdX2qtpcVZtXr3lpD6VJWi59hMe9wKYkpyU5FrgImJ7VZxq4uGtfCNxRVdXD2JLGZPWwO6iqI0muAG4DVgHXVdWeJJ8EdlbVNPBF4O+T7AWeZiZgJK1gQ4cHQFXtAHbMWnfVQPtnwJ/2MZakyTBRF0wlrRyGh6QmhoekJoaHpCaGh6QmhoekJoaHpCaGh6QmhoekJoaHpCaGh6QmhoekJoaHpCaGh6QmhoekJoaHpCaGh6QmhoekJoaHpCaGh6QmhoekJoaHpCaGh6QmhoekJoaHpCaGh6QmhoekJoaHpCa9hEeS85I8kmRvkivn2H5Jkh8k2dV9LutjXEnjs3rYHSRZBXwBeBuwD7g3yXRVPTSr681VdcWw40maDH0ceZwD7K2qJ6rqeeAmYFsP+5U0wYY+8gA2AE8OLO8DXj9Hv3ckeTPwKPDBqnpydockU8AUwOp1a3n2gmd7KO/F6cT/eO24S5h4f/wH94+7hIl39RC/HdUF068Dp1bV7wO3A9fP1amqtlfV5qravGrt8SMqTVKLPsJjP7BxYPmUbt0vVNXBqnquW7wWeF0P40oaoz7C415gU5LTkhwLXARMD3ZIsn5g8QLg4R7GlTRGQ1/zqKojSa4AbgNWAddV1Z4knwR2VtU08BdJLgCOAE8Dlww7rqTx6uOCKVW1A9gxa91VA+2PAh/tYyxJk8EnTCU1MTwkNTE8JDUxPCQ1MTwkNTE8JDUxPCQ1MTwkNTE8JDUxPCQ1MTwkNTE8JDUxPCQ1MTwkNTE8JDUxPCQ1MTwkNTE8JDUxPCQ1MTwkNTE8JDUxPCQ1MTwkNTE8JDUxPCQ1MTwkNTE8JDXpJTySXJfkqSQPzrM9ST6XZG+SB5Kc3ce4ksanryOPLwHnLbD97cCm7jMFXN3TuJLGpJfwqKq7gKcX6LINuKFm3A2cmGR9H2NLGo9RXfPYADw5sLyvW/dLkkwl2Zlk588P/WREpUlqMVEXTKtqe1VtrqrNq9YeP+5yJC1gVOGxH9g4sHxKt07SCjWq8JgG3t3ddTkXOFRVB0Y0tqRlsLqPnSS5EdgCrEuyD/gEcAxAVV0D7AC2AnuBnwDv6WNcSePTS3hU1TsX2V7A+/oYS9JkmKgLppJWDsNDUhPDQ1ITw0NSE8NDUhPDQ1ITw0NSE8NDUhPDQ1ITw0NSE8NDUhPDQ1ITw0NSE8NDUhPDQ1ITw0NSE8NDUhPDQ1ITw0NSE8NDUhPDQ1ITw0NSE8NDUhPDQ1ITw0NSE8NDUhPDQ1KTXsIjyXVJnkry4DzbtyQ5lGRX97mqj3EljU8vf9E18CXg88ANC/T5dlWd39N4ksaslyOPqroLeLqPfUlaGfo68liKNyS5H/ge8OGq2jO7Q5IpYApgzeoTOO0jh0dY3sryn3/z0nGXMPFu23DPuEuYeFcP8dtRhcd9wKur6nCSrcAtwKbZnapqO7AdYO2ak2tEtUlqMJK7LVX1TFUd7to7gGOSrBvF2JKWx0jCI8nJSdK1z+nGPTiKsSUtj15OW5LcCGwB1iXZB3wCOAagqq4BLgQuT3IE+ClwUVV5WiKtYL2ER1W9c5Htn2fmVq6kFwmfMJXUxPCQ1MTwkNTE8JDUxPCQ1MTwkNTE8JDUxPCQ1MTwkNTE8JDUxPCQ1MTwkNTE8JDUxPCQ1MTwkNTE8JDUxPCQ1MTwkNTE8JDUxPCQ1MTwkNTE8JDUxPCQ1MTwkNTE8JDUxPCQ1MTwkNRk6PBIsjHJnUkeSrInyfvn6JMkn0uyN8kDSc4edlxJ49XHX3R9BPhQVd2X5ATgO0lur6qHBvq8HdjUfV4PXN19S1qhhj7yqKoDVXVf134WeBjYMKvbNuCGmnE3cGKS9cOOLWl8er3mkeRU4CzgnlmbNgBPDizv41cDRtIK0sdpCwBJXgZ8FfhAVT3TuI8pYApgzeoT+ipN0jLo5cgjyTHMBMeXq+prc3TZD2wcWD6lW/dLqmp7VW2uqs3Hrjq+j9IkLZM+7rYE+CLwcFV9dp5u08C7u7su5wKHqurAsGNLGp8+TlveBLwL2J1kV7fuY8CrAKrqGmAHsBXYC/wEeE8P40oao6HDo6r+BcgifQp437BjSZocPmEqqYnhIamJ4SGpieEhqYnhIamJ4SGpieEhqYnhIamJ4SGpieEhqYnhIamJ4SGpieEhqYnhIamJ4SGpieEhqYnhIamJ4SGpieEhqYnhIamJ4SGpieEhqYnhIamJ4SGpieEhqYnhIamJ4SGpieEhqcnQ4ZFkY5I7kzyUZE+S98/RZ0uSQ0l2dZ+rhh1X0nit7mEfR4APVdV9SU4AvpPk9qp6aFa/b1fV+T2MJ2kCDH3kUVUHquq+rv0s8DCwYdj9Sppsqar+dpacCtwFnFlVzwys3wJ8FdgHfA/4cFXtmeP3U8BUt3gm8GBvxfVjHfDDcRcxwHoWNmn1wOTV9JqqOqHlh72FR5KXAf8M/FVVfW3Wtt8A/q+qDifZCvxdVW1aZH87q2pzL8X1ZNJqsp6FTVo9MHk1DVNPL3dbkhzDzJHFl2cHB0BVPVNVh7v2DuCYJOv6GFvSePRxtyXAF4GHq+qz8/Q5uetHknO6cQ8OO7ak8enjbsubgHcBu5Ps6tZ9DHgVQFVdA1wIXJ7kCPBT4KJa/Hxpew+19W3SarKehU1aPTB5NTXX0+sFU0m/PnzCVFITw0NSk4kJjyQvT3J7kse675Pm6ffzgcfcp5ehjvOSPJJkb5Ir59h+XJKbu+33dM+2LKsl1HRJkh8MzMtly1jLdUmeSjLnMziZ8bmu1geSnL1ctRxFTSN7PWKJr2uMdI6W7RWSqpqID/AZ4MqufSXw6Xn6HV7GGlYBjwOnA8cC9wNnzOrz58A1Xfsi4OZlnpel1HQJ8PkR/Tm9GTgbeHCe7VuBbwABzgXumYCatgD/OKL5WQ+c3bVPAB6d489rpHO0xJqOeo4m5sgD2AZc37WvB/5kDDWcA+ytqieq6nngpq6uQYN1fgV4ywu3ocdY08hU1V3A0wt02QbcUDPuBk5Msn7MNY1MLe11jZHO0RJrOmqTFB6vrKoDXfu/gVfO029Nkp1J7k7Sd8BsAJ4cWN7Hr07yL/pU1RHgEPCKnus42poA3tEdAn8lycZlrGcxS6131N6Q5P4k30jye6MYsDulPQu4Z9amsc3RAjXBUc5RH895LFmSbwInz7Hp44MLVVVJ5ruH/Oqq2p/kdOCOJLur6vG+a11hvg7cWFXPJfkzZo6M/mjMNU2S+5j59+aF1yNuARZ8PWJY3esaXwU+UAPveY3TIjUd9RyN9Mijqt5aVWfO8bkV+P4Lh27d91Pz7GN/9/0E8C1mUrQv+4HB/2qf0q2bs0+S1cBalvdp2UVrqqqDVfVct3gt8LplrGcxS5nDkaoRvx6x2OsajGGOluMVkkk6bZkGLu7aFwO3zu6Q5KQkx3Xtdcw83Tr7/xsyjHuBTUlOS3IsMxdEZ9/RGazzQuCO6q44LZNFa5p1vnwBM+e04zINvLu7o3AucGjgdHQsRvl6RDfOgq9rMOI5WkpNTXM0iivQS7wi/Argn4DHgG8CL+/Wbwau7dpvBHYzc8dhN3DpMtSxlZmr0Y8DH+/WfRK4oGuvAf4B2Av8O3D6COZmsZr+GtjTzcudwO8sYy03AgeA/2XmXP1S4L3Ae7vtAb7Q1bob2DyC+VmspisG5udu4I3LWMsfAgU8AOzqPlvHOUdLrOmo58jH0yU1maTTFkkriOEhqYnhIamJ4SGpieEhqYnhIamJ4SGpyf8DkT4FQkDUuTwAAAAASUVORK5CYII=\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "imgs,labels = training_set_generator.next()\n",
    "bottleneck_feature_example = vgg.predict(imgs[0:1])\n",
    "print(bottleneck_feature_example.shape)\n",
    "plt.imshow(bottleneck_feature_example[0][:,:,0])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Top layer"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from tensorflow.keras.layers import Conv2D, MaxPooling2D, Flatten, Dense, Dropout, InputLayer \n",
    "from tensorflow.keras.models import Sequential \n",
    "from tensorflow.keras import optimizers \n",
    "\n",
    "model = Sequential() \n",
    "model.add(vgg_model) \n",
    "model.add(Dense(512, activation='relu')) \n",
    "model.add(Dropout(0.3)) \n",
    "model.add(Dense(512, activation='relu')) \n",
    "model.add(Dropout(0.3)) \n",
    "model.add(Dense(2, activation='softmax')) \n",
    "\n",
    "model.compile(loss='categorical_crossentropy', \n",
    "              optimizer=optimizers.RMSprop(lr=2e-5), \n",
    "              metrics=['accuracy'])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Training"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def train_vgg( model,\n",
    "               target_size,\n",
    "               dataset_path,\n",
    "               training_path_prefix,\n",
    "               test_path_prefix,                        \n",
    "               history_file_path,\n",
    "               history_filename,\n",
    "               checkpoint_path,\n",
    "               checkpoint_prefix,\n",
    "               number_of_epochs,\n",
    "               tensorboard_log_path\n",
    "            ):\n",
    "   \n",
    "    step_size_train=training_set_generator.n//training_set_generator.batch_size\n",
    "    step_size_validation=test_set_generator.n//test_set_generator.batch_size\n",
    "\n",
    "    check_pointer = ModelCheckpoint(\n",
    "            checkpoint_path + '%s_weights.{epoch:02d}-{val_loss:.2f}.hdf5' % checkpoint_prefix, \n",
    "            monitor='val_loss', \n",
    "            mode='auto', \n",
    "            save_best_only=True\n",
    "    )\n",
    "    \n",
    "    tensorboard_logger = TensorBoard( \n",
    "        log_dir=tensorboard_log_path, histogram_freq=0,  \n",
    "          write_graph=True, write_images=True\n",
    "    )\n",
    "    tensorboard_logger.set_model(model)\n",
    "\n",
    "    csv_logger = CSVLogger(filename=history_file_path+history_filename)\n",
    "    history = model.fit_generator(\n",
    "            training_set_generator,\n",
    "            steps_per_epoch=step_size_train,\n",
    "            epochs=number_of_epochs,\n",
    "            validation_data=test_set_generator,\n",
    "            validation_steps=step_size_validation,\n",
    "            callbacks=[check_pointer, csv_logger,tensorboard_logger],\n",
    "            verbose=True        \n",
    "    )"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "#TODO train"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.5.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
